import { Serializable } from "../util/util";

function mapAllSource(){
    for(let name in Game.rooms){
        let room = Game.rooms[name];
        if(!room.memory){
            room.memory=Memory.rooms[name]={};
        }
        if(room.memory.sources==undefined){
            getSources(room);
        }
    }
    let roomsLength=0;
    let rooms=Memory.rooms;
    if(rooms instanceof Object){
        roomsLength=Object.getOwnPropertyNames(rooms).length;
    }else{
        for(let _name in Memory.rooms){
            roomsLength++;
        }
    }
}
export function mapAll(){
    mapAllSource();

    for(let roomName in Game.rooms){
        let room = Game.rooms[roomName];
        if(!room){
            // Memory.rooms[roomName].exploring=false;
            continue;
        }
        if(room.controller && room.controller.my){
            getRoomDomain(room);
        }
    }
}
/**
 * 
 * @param {Room} room
 * @return {string[]} ids
 */
export function getSources(room){
    if(room.memory.sources!=undefined){
        return room.memory.sources;
    }

    let sources=room.find(FIND_SOURCES);
    let ids=[];
    for(let src of sources){
        ids.push(src.id);
    }
    return room.memory.sources=ids;
}

/**
 * 
 * @param {Room} room 
 */
export function mapRoomDomain(room){
    let exits=Game.map.describeExits(room.name);
    let roomNames=new Set([room.name]);
    let connectedRoomNames=[];
    for(let findExit in exits){
        if(exits[findExit]==undefined){
            continue;
        }
        let roomName=exits[findExit];
        let mem=Memory.rooms[roomName];
        if(!mem){
            mem=Memory.rooms[roomName]={};
        }
        // if(mem.enemy){
        //     continue;
        // }
        connectedRoomNames.push(roomName);
        roomNames.add(roomName);
    }

    for(let roomName of connectedRoomNames){
        let exits=Game.map.describeExits(roomName);
        if(typeof exits != 'object'){
            console.log('exits',exits, roomName);
            continue;
        }
        const exitDirections=[1,3,5,7];
        for(let findExit of exitDirections){
            if(!exits[findExit]){
                continue;
            }
            let nextRoomName=exits[findExit];
            if(Game.map.getRoomLinearDistance(room.name, nextRoomName)>1){
                continue;
            }
            let mem=Memory.rooms[nextRoomName];
            if(!mem){
                mem=Memory.rooms[roomName]={};
            }
            // if(mem.enemy){
            //     continue;
            // }
            roomNames.add(nextRoomName);
        }
    }
    for(let roomName of roomNames){
        if(!Memory.rooms[roomName]){
            Memory.rooms[roomName]={};
        }
        Memory.rooms[roomName].mainRoomName=undefined;
    }
    let ans=[];
    for(let roomName of roomNames){
        let mem=Memory.rooms[roomName];
        if(mem.mainRoomName==undefined){
            mem.mainRoomName=room.name;
        }else if(mem.mainRoomName==room.name){
            mem.mainRoomName=room.name;
        }
        ans.push(roomName);
    }
    room.memory.domain=ans;
    console.log("remap domain:",ans);
    return ans;
}
/**
 * 
 * @param {Room} room 
 * @returns {string[]}
 */
export function getRoomDomain(room, ignoreEnemy = false){
    let domain=room.memory.domain;
    if(domain===undefined || Game.time%10000===2){
        domain=mapRoomDomain(room);
    }
    if(ignoreEnemy){
        return domain.filter((roomName)=>!Memory.rooms[roomName].enemy);
    }
    return domain;
}

/**
 * 
 * @param {Room} room 
 * @returns {RoomTerrain}
 */
export function getRoomTerrain(room){
    if(room.__roomTerrain !== undefined){
        return room.__roomTerrain;
    }
    return room.__roomTerrain = room.getTerrain();
    
}

/**
 * 
 * @param {AnyCreep} creep 
 * @returns {Boolean}
 */
function isCreepArmed(creep){
    for(const body of creep.body){
        if([HEAL, ATTACK, RANGED_ATTACK].some((type)=>type===body.type)){
            return true;
        }
    }
    return false;
}
function isStructureArmed(structure){
    switch(structure.structureType){
        case STRUCTURE_EXTRACTOR:
        case STRUCTURE_EXTENSION:
        case STRUCTURE_CONTAINER:
        case STRUCTURE_CONTROLLER:
        case STRUCTURE_FACTORY:
        case STRUCTURE_LAB:
        case STRUCTURE_LINK:
        case STRUCTURE_OBSERVER:
        case STRUCTURE_PORTAL:
        case STRUCTURE_ROAD:
        case STRUCTURE_STORAGE:
            return false;
        default:
            return true;
    }
}

export function sortHostiles(hostiles, centerPos){
    hostiles.sort((a, b) => {
        let isArmed = (target)=>{
            if(target.__isArmed instanceof Boolean){
                return target.__isArmed;
            }
            if(target instanceof Creep){
                return target.__isArmed = isCreepArmed(target);
            }else if(target instanceof Structure){
                return target.__isArmed = isStructureArmed(target);
            }else{
                throw new Error("unknown type");
            }
        }
        const armedA = isArmed(a);
        const armedB = isArmed(b);
        if(armedA ^ armedB){
            return armedA - armedB;
        }
        return distCmp = centerPos.getRangeTo(a.pos) - 
            centerPos.getRangeTo(b.pos);
    });
    for(const hostile of hostiles){
        hostile.__isArmed = undefined;
    }
}

/**
 * 
 * @param {Room} room 
 * @param {Boolean} countSourceKeepers 
 * @param {Boolean} ignoreCreeps 
 * @param {Boolean} ignoreStructures 
 * @returns {(AnyCreep|AnyStructure)[]}
 */
export function findRoomHostiles(room, countSourceKeepers=false, ignoreCreeps = false, ignoreStructures = false){
    if(!room){
        return [];
    }

    if(room.__roomHostile !== undefined){
        return room.__roomHostile;
    }

    let targets = [];
    if(!ignoreStructures){
        targets.push(...room.find(FIND_HOSTILE_STRUCTURES,{
            filter(structure){
                return (countSourceKeepers || structure.owner.username!=='Source Keeper') && 
                    (structure.structureType !== STRUCTURE_CONTROLLER);
            }
        }));
    }
    if(!ignoreCreeps){
        targets.push(...room.find(FIND_HOSTILE_CREEPS,{
            filter(creep){
                return (countSourceKeepers || creep.owner.username!=='Source Keeper');
            }
        }));
    }
    return room.__roomHostile = targets;
}
// const FIND_HOSTILE_DEFAULT_INCLUDE=[
//     PowerCreep,
//     Creep,
//     Structure,
// ];
// export function findHostiles(mainRoom, include = undefined){

// }
    /**
 * @param {Room} mainRoom
 * @param {Boolean} countSourceKeepers 
 * @param {Boolean} ignoreCreeps 
 * @param {Boolean} ignoreStructures 
 * @returns {(AnyCreep | AnyStructure)[]}
 */
export function getHostiles(mainRoom, countSourceKeepers=false, ignoreCreeps = false, ignoreStructures = false){
    if(mainRoom.__hostiles !== undefined){
        return mainRoom.__hostiles;
    }

    let domain = getRoomDomain(mainRoom, true);

    let targets = [];
    for(let roomName of domain){
        let room = Game.rooms[roomName];
        if(!room){
            continue;
        }
        targets.push(...findRoomHostiles(room, countSourceKeepers, ignoreCreeps, ignoreStructures));
    }
    mainRoom.__hostiles = targets;
    return targets;
}